Scroll to navigation

FUTEX(2) Linux Programmer's Manual FUTEX(2)

名前

futex - 高速ユーザ空間ロック機構のシステムコール

書式

#include <linux/futex.h>
#include <sys/time.h>

int futex(int *uaddr, int op, int val, const struct timespec *timeout,

int *uaddr2, int val3);

説明

futex() システムコールは、 指定したアドレスの値が変更されるのをプログラムが待つ手段や 特定のアドレスに対して待機中のプロセスを wake (起床) させる手段を提供する (プロセスが異なれば同じメモリに対するアドレスも同じではないかもしれないが、 カーネルは異なる位置にマップされた同じメモリを futex() で使えるよう内部でマップする)。 典型的には、futex は futex(7) に記されているように、 共有メモリ中のロックが競合する場合の処理を実装するのに用いられる。

futex(7) の操作がユーザ空間で競合なく完了しなかった場合、 カーネルに仲裁させるためにシステムコールを呼ぶ必要がある。 仲裁というのは、呼び出しプロセスを sleep (起床待ち) させたり、反対に 待ちプロセスを wake させたりすることを意味する。

この関数を呼び出すプロセスは futex(7) に記述されているセマンティクスに忠実であることが要求される。 このセマンティクスには移植不可能なアセンブリ命令を書くことが含まれる。 このことは言い換えると futex のユーザのほとんどは実際はライブラリの作者であり、 一般アプリケーションの開発者ではないということである。

uaddr 引き数は、カウンタを格納する、 アラインメントの揃った int 型変数を指している必要がある。 実行する操作は op 引き数を介して、値 val とともに渡される。

現在のところ 5 つの操作が定義されている:

この操作は futex アドレス uaddr に指定された値 val がまだ格納されているかどうかを不可分操作で検証し、 sleep 状態で この futex アドレスに対して FUTEX_WAKE が実行されるのを待つ。 timeout 引き数が NULL でない場合、その内容は 待ち時間の最大値を表す。NULL の場合は無限大を表す。 引き数 uaddr2val3 は無視される。

futex(7) に照らし合わせると、この呼び出しは カウントのデクリメントで負の値 (競合を表す) になった場合に実行され、 別のプロセスがその futex を解放し FUTEX_WAKE の操作を実行するまで sleep する。

この操作では指定した futex アドレスに対して待ち状態の (すなわち FUTEX_WAIT 中の) 最大 val 個のプロセスを wake させる。 引き数 timeout, uaddr2, val3 は無視される。

futex(4) に照らし合わせると、 この操作は カウントのインクリメントで待ちプロセスがあると判明し、 futex 値が 1 に設定された (利用可能であることを表す) 場合に実行される。

非同期の wake に対応するため、この操作はファイルディスクリプタを futex に 関連づける。 別のプロセスが FUTEX_WAKE を実行すると、プロセスは val で渡されたシグナル番号のシグナルを受信する。 呼び出しプロセスは使用後、返されたファイルディスクリプタを クローズしなければならない。 引き数 timeout, uaddr2, val3 は無視される。

競合状態を防止するため、呼び出しプロセスは FUTEX_FD が返ったあと futex が up されたかどうかを確認しなければならない。

FUTEX_FD はもともと競合が起きやすかったため、 Linux 2.6.26 以降で削除されている。

この操作は、 FUTEX_WAKE が使われていて、かつ wake されている全てのプロセスが 他の futex を取得する必要がある場合に、 「獣の群れの暴走 (thundering herd)」効果を避けるために導入された。 この呼び出しは val 個のプロセスを wake し、アドレス uaddr2 で futex を待っている他の全てのプロセスを再度キューにいれる。 引き数 timeoutval3 は無視される。
故意に FUTEX_REQUEUE を使う場合に競合が起こるため、 FUTEX_CMP_REQUEUE が導入された。これは FUTEX_REQUEUE と似ているが、場所 uaddr に値 val3 がまだ保持されているかを最初にチェックする。 保持されていない場合、操作はエラー EAGAIN で失敗する。引き数 timeout は無視される。

返り値

どの操作が実行されたかによって、 成功時の返り値の意味が変わる。

プロセスが FUTEX_WAKE の呼び出しで wake すると 0 を返す。 タイムアウトの場合、操作はエラー ETIMEOUT で失敗する。 futex が指定された値と等しくない場合、 エラー EWOULDBLOCK で失敗する。 シグナルを受信するか (signal(7) 参照) 他の偽の wake があった場合には、エラー EINTR で失敗する。
wake したプロセスの数を返す。
futex に関連づけられた新たなファイルディスクリプタを返す。
wake したプロセスの数を返す。
wake したプロセスの数を返す。

エラーの場合、全ての操作で -1 が返り、 errno がエラーの内容を示す値に設定される。

エラー

futex メモリに読み込みアクセス権がなかった。
FUTEX_CMP_REQUEUE で予期しない futex 値が見つかった (これは競合を示しているかもしれない。 この場合は安全な FUTEX_WAKE を使うこと)。
ユーザ空間から timeout の情報を取得する際にエラーが発生した。
操作が定義されていない。またはページ・アラインメントでエラーが発生した。
オープンされているファイルの総数がシステムの制限に達した。
op に無効な操作が指定された。

バージョン

最初の futex 対応は Linux 2.5.7 で組み込まれたが、 上記のセマンティクスとは異なる。 ここで示されているセマンティクスを持つ 4 つの引き数のシステムコールは、Linux 2.5.40 で導入された。 Linux 2.5.70 では 1 つの引き数が追加された。 Linux 2.6.7 では 6 番目の引き数が追加された。 これは汚く、s390 アーキテクチャ上の特別のものである。

準拠

このシステムコールは Linux 独自である。

注意

繰り返すが、裸の futex はエンドユーザが容易に使うことのできる概念として 意図されたものではない (glibc にはこのシステムコールに対するラッパー関数はない)。 実装者は、アセンブリ言語に慣れており、以下に挙げる futex ユーザ空間ライブラリの ソースを読み終えていることが要求される。

関連項目

futex(7)

Fuss, Futexes and Furwocks: Fast Userlevel Locking in Linux (proceedings of the Ottawa Linux Symposium 2002), futex の使用例ライブラリ, futex-*.tar.bz2 <URL:ftp://ftp.nl.kernel.org/pub/linux/kernel/people/rusty/>.

2008-11-27 Linux